/*
* Copyright (c) 2022 Talkweb Co., Ltd.
*
* HDF is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
* See the LICENSE file in the root of this repository for complete details.
*/

#include "i2c_if.h"          
#include "gpio_if.h"        
#include "hdf_log.h"        
#include "osal_time.h"
#include "hdf_device_desc.h"
#include "device_resource_if.h"

#define HDF_LOG_TAG "at24_drv_log"

#define I2C_RD_CMD 456
#define I2C_WR_CMD 789

#define CHECK_LIGHT_NULL_PTR_RETURN_VALUE(ptr, ret) do { \
    if ((ptr) == NULL) { \
        HDF_LOGE("%s:line %d pointer is null and return ret", __func__, __LINE__); \
        return (ret); \
    } \
} while (0)
/*
#define CHECK_LIGHT_NULL_PTR_RETURN(ptr) do { \
    if ((ptr) == NULL) { \
        HDF_LOGE("%s:line %d pointer is null and return", __func__, __LINE__); \
        return; \
    } \
} while (0)
*/
#define CHECK_LIGHT_PARSER_RESULT_RETURN_VALUE(ret, str) do { \
    if (ret != HDF_SUCCESS) { \
        HDF_LOGE("%s:line %d %s fail, ret = %d!", __func__, __LINE__, str, ret); \
        return HDF_FAILURE; \
    } \
} while (0)


struct TpI2cDevice {
    uint16_t busId;               
    uint16_t addr;               
    uint16_t regLen;             
    DevHandle i2cHandle;          
};

static struct TpI2cDevice tpDevice;

static int TpI2cReadWrite(struct TpI2cDevice *tpDevice, uint16_t regAddr,
    uint8_t *regData, uint32_t dataLen, uint8_t flag)
{
    int index = 0;
    unsigned char regBuf[2] = {0};
    struct I2cMsg msgs[2] = {0};

    if (tpDevice->regLen == 1) { 
        regBuf[index++] = regAddr & 0xFF;
    } else {
        regBuf[index++] = (regAddr >> 8) & 0xFF;
        regBuf[index++] = regAddr & 0xFF;
    }

    msgs[0].addr = tpDevice->addr;
    msgs[0].flags = 0; 
    msgs[0].len = tpDevice->regLen;
    msgs[0].buf = regBuf;

    msgs[1].addr = tpDevice->addr;
    msgs[1].flags = (flag == 1) ? I2C_FLAG_READ : 0; 
    msgs[1].len = dataLen;
    msgs[1].buf = regData;

    if (I2cTransfer(tpDevice->i2cHandle, msgs, 2) != 2) {
        HDF_LOGD("%s: i2c read err", __func__);
        return HDF_FAILURE;
    }
    
    return HDF_SUCCESS;
}

static inline int TpI2cReadReg(struct TpI2cDevice *tpDevice, uint16_t regAddr,
    uint8_t *regData, uint32_t dataLen)
{
    return TpI2cReadWrite(tpDevice, regAddr, regData, dataLen, 1);
}

static inline int TpI2cWriteReg(struct TpI2cDevice *tpDevice, uint16_t regAddr,
    uint8_t *regData, uint32_t dataLen)
{
    return TpI2cReadWrite(tpDevice, regAddr, regData, dataLen, 0);
}


static int32_t at24_init(void)
{  
/*      
    tpDevice.busId = 5;
    tpDevice.addr = 0x50;
    tpDevice.regLen = 2;
    tpDevice.i2cHandle = NULL;
*/   
    tpDevice.i2cHandle = I2cOpen(tpDevice.busId);
    if (tpDevice.i2cHandle == NULL) {
        HDF_LOGD("%s: Open I2c:%u fail!", __func__, tpDevice.busId);
        return HDF_FAILURE;
    }   
    return HDF_SUCCESS;
}

static int32_t GetAT24ConfigData(const struct DeviceResourceNode *node)
{    
    int32_t ret; 

    struct DeviceResourceIface *parser = NULL;
    const struct DeviceResourceNode *at24 = NULL;

    CHECK_LIGHT_NULL_PTR_RETURN_VALUE(node, HDF_ERR_INVALID_PARAM);

    parser = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
    CHECK_LIGHT_NULL_PTR_RETURN_VALUE(parser, HDF_ERR_INVALID_PARAM);
    CHECK_LIGHT_NULL_PTR_RETURN_VALUE(parser->GetChildNode, HDF_ERR_INVALID_PARAM);

    at24 = parser->GetChildNode(node, "at24Attr");
    CHECK_LIGHT_NULL_PTR_RETURN_VALUE(at24, HDF_ERR_INVALID_PARAM);    

    ret = parser->GetUint16(at24, "busId", &(tpDevice.busId), 0);
    CHECK_LIGHT_PARSER_RESULT_RETURN_VALUE(ret, "busId");
    ret = parser->GetUint16(at24, "addr", &(tpDevice.addr), 0);
    CHECK_LIGHT_PARSER_RESULT_RETURN_VALUE(ret, "addr");
    ret = parser->GetUint16(at24, "regLen", &(tpDevice.regLen), 0);
    CHECK_LIGHT_PARSER_RESULT_RETURN_VALUE(ret, "regLen");
    HDF_LOGE("busId: %hu, addr: 0x%hx, regLen: %hu", tpDevice.busId, tpDevice.addr, tpDevice.regLen);

    return HDF_SUCCESS;
}

int32_t HdfSensorDriverDispatch(struct HdfDeviceIoClient *client, int id, struct HdfSBuf *data, struct HdfSBuf *reply)
{
    uint16_t addr = 0;
    uint8_t value = 0;

    if (client == NULL || client->device == NULL){
        HDF_LOGD("i2c sensor driver device is NULL");
        return HDF_ERR_INVALID_OBJECT;
    }

    if(id == I2C_WR_CMD){
        if (!HdfSbufReadUint16(data, &addr)) {
            HDF_LOGD("%s: data addr fail", __func__);
            return HDF_FAILURE;
        }
        if (!HdfSbufReadUint8(data, &value)) {
            HDF_LOGD("%s: data value fail", __func__);
            return HDF_FAILURE;
        }

        if(TpI2cWriteReg(&tpDevice, addr, &value, 1) != HDF_SUCCESS)
            return HDF_FAILURE;

        if (!HdfSbufWriteString(reply, "write success")) {
            HDF_LOGE("%s: data string fail", __func__);
        }    
        return HDF_SUCCESS;
    }
    if (id == I2C_RD_CMD) {               
        if (!HdfSbufReadUint16(data, &addr)) {
            HDF_LOGD("%s: data addr fail", __func__);
            return HDF_FAILURE;
        }
        
        if(TpI2cReadReg(&tpDevice, addr, &value, 1) != HDF_SUCCESS)
            return HDF_FAILURE;        
        if (!HdfSbufWriteUint8(reply, value)) {
            HDF_LOGD("%s: reply value fail", __func__);
            return HDF_FAILURE;
        }
        if (!HdfSbufWriteString(reply, "read success")) {
            HDF_LOGE("%s: reply string fail", __func__);
        } 
        return HDF_SUCCESS;
    } 

    return HDF_FAILURE;
}

int32_t HdfSensorDriverBind(struct HdfDeviceObject *deviceObject)
{
    if (deviceObject == NULL) {
        return HDF_FAILURE;
    }
    static struct IDeviceIoService sensorService = {
        .Dispatch = HdfSensorDriverDispatch,
    };
    deviceObject->service = &sensorService;
    HDF_LOGD("i2c at24 driver bind success");
    return HDF_SUCCESS;
}

int32_t HdfSensorDriverInit(struct HdfDeviceObject *deviceObject)
{   
    if (GetAT24ConfigData(deviceObject->property) != HDF_SUCCESS) {
        HDF_LOGE("%s: get at24 config fail!", __func__);
        return HDF_FAILURE;
    }
    if(at24_init() != HDF_SUCCESS){
        HDF_LOGE("i2c at24 driver Init failed");
        return -1;
    }
        
    HDF_LOGD("i2c at24 driver Init success");
    return 0;
}

void HdfSensorDriverRelease(struct HdfDeviceObject *deviceObject)
{
    I2cClose(tpDevice.i2cHandle);
    HDF_LOGD("i2c at24 driver release success");
    return;
}


struct HdfDriverEntry g_SensorDriverEntry = {
    .moduleVersion = 1,
    .moduleName = "at24_drv",
    .Bind = HdfSensorDriverBind,
    .Init = HdfSensorDriverInit,
    .Release = HdfSensorDriverRelease,
};

HDF_INIT(g_SensorDriverEntry);